package com.ermax.aircond.maintain.service;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ermax.aircond.common.dao.UserDetailDao;
import com.ermax.aircond.common.dao.UserGroupDao;
import com.ermax.aircond.common.domain.ReadMachineData;
import com.ermax.aircond.common.domain.UserDetail;
import com.ermax.aircond.common.domain.UserGroup;
import com.ermax.aircond.common.domain.WriteMachineData;
import com.ermax.aircond.common.parameter.Status;
import com.ermax.aircond.common.service.ReadMachineDataService;
import com.ermax.aircond.common.service.WriteMachineDataService;
import com.ermax.aircond.maintain.dao.BuildingDao;
import com.ermax.aircond.maintain.dao.FloorDao;
import com.ermax.aircond.maintain.dao.MachineDao;
import com.ermax.aircond.maintain.dao.RoomDao;
import com.ermax.aircond.maintain.domain.Building;
import com.ermax.aircond.maintain.domain.Floor;
import com.ermax.aircond.maintain.domain.Machine;
import com.ermax.aircond.maintain.domain.Room;
import com.ermax.aircond.maintain.service.MaintainService;
import com.ermax.aircond.util.service.MachineCommandService;

@Service("maintainService")
public class MaintainService implements Serializable {

	private static final long serialVersionUID = 1L;
	@Resource(name = "userGroupDao")
	private UserGroupDao userGroupDao;

	@Resource(name = "userDetailDao")
	private UserDetailDao userDetailDao;

	@Resource(name = "buildingDao")
	private BuildingDao buildingDao;

	@Resource(name = "floorDao")
	private FloorDao floorDao;

	@Resource(name = "roomDao")
	private RoomDao roomDao;

	@Resource(name = "machineDao")
	private MachineDao machineDao;

	@Resource(name = "machineCommandService")
	private MachineCommandService machineCommandService;
	
	@Resource(name = "writeMachineDataService")
	private WriteMachineDataService writeMachineDataService;
	
	@Resource(name = "readMachineDataService")
	private ReadMachineDataService readMachineDataService;

	@Transactional(readOnly = true)
	public UserGroup getUserGroupById(long id) throws Exception {
		return userGroupDao.getById(id);
	}

	@Transactional(readOnly = true)
	public List<UserGroup> getAllUserGroups() throws Exception {
		return userGroupDao.findAll();
	}

	@Transactional(readOnly = true)
	public List<UserGroup> getUserGroups(String search) throws Exception {
		return userGroupDao.findUserGroupByKeyword(search);
	}

	@Transactional(readOnly = true)
	public List<UserGroup> getUserGroupsNotIn(String search) throws Exception {
		return userGroupDao.findUserGroupNotIn(search);
	}
	
	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void createUserGroup(UserGroup userGroup, String userName) throws Exception {
		Date currentDate = new Date();
		userGroup.setCreateUser(userName);
		userGroup.setCreateDate(currentDate);
		userGroup.setUpdateUser(userName);
		userGroup.setUpdateDate(currentDate);
		userGroupDao.create(userGroup);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void updateUserGroup(UserGroup userGroup, String userName) throws Exception {
		Date currentDate = new Date();
		userGroup.setUpdateUser(userName);
		userGroup.setUpdateDate(currentDate);
		userGroupDao.update(userGroup);

	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void deleteUserGroup(UserGroup userGroup) throws Exception {
		userGroupDao.delete(userGroup);
	}

	@Transactional(readOnly = true)
	public List<UserDetail> getAllUserDetails() throws Exception {
		return userDetailDao.findAll();
	}
	
	@Transactional(readOnly = true)
	public List<UserDetail> findUserDetailsNotInGroup(String groupName, String userName) throws Exception {
		List<UserGroup> userGroups = userGroupDao.findUserGroupByKeyword(groupName);
		return userDetailDao.findUserDetailsNotInGroup(userGroups, userName);
	}
	
	@Transactional(readOnly = true)
	public UserDetail getUserDetailById(long id) throws Exception {
		return userDetailDao.getById(id);
	}

	public List<UserDetail> getUserDetails(String search) throws Exception {
		return getUserDetails(null, search);
	}

	public List<UserDetail> getUserDetails(UserGroup userGroup) throws Exception {
		return getUserDetails(userGroup, null);
	}

	@Transactional(readOnly = true)
	public List<UserDetail> getUserDetails(UserGroup userGroup, String search) throws Exception {
		return userDetailDao.findUserDetails(userGroup, search);
	}

	@Transactional
	@PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SUPERVISOR')")
	public void createUserDetail(UserDetail userDetail, String userName) throws Exception {
		Date currentDate = new Date();
		userDetail.setCreateDate(currentDate);
		userDetail.setCreateUser(userName);
		userDetail.setUpdateDate(currentDate);
		userDetail.setUpdateUser(userName);
		userDetailDao.create(userDetail);
	}

	@Transactional
	@PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SUPERVISOR')")
	public void updateUserDetail(UserDetail userDetail, String userName) throws Exception {
		userDetail.setUpdateDate(new Date());
		userDetail.setUpdateUser(userName);
		userDetailDao.update(userDetail);
	}

	@Transactional
	@PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SUPERVISOR')")
	public void deleteUserDetail(UserDetail userDetail) throws Exception {
		userDetailDao.delete(userDetail);

	}

	@Transactional(readOnly = true)
	public Building getBuildingById(long id) throws Exception {
		return buildingDao.getById(id);
	}

	@Transactional(readOnly = true)
	public List<Building> getAllBuildings() throws Exception {
		return buildingDao.findAll();
	}

	@Transactional(readOnly = true)
	public List<Building> getAllBuildings(String status) throws Exception {
		return buildingDao.findAll(status);
	}

	@Transactional(readOnly = true)
	public List<Building> getBuildings(String search) throws Exception {
		return buildingDao.findBuildings(search);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void createBuilding(Building building, String userName) throws Exception {
		Date currentDate = new Date();
		building.setCreateDate(currentDate);
		building.setCreateUser(userName);
		building.setUpdateDate(currentDate);
		building.setUpdateUser(userName);
		buildingDao.create(building);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void updateBuilding(Building building, String userName) throws Exception {
		Date currentDate = new Date();
		building.setUpdateDate(currentDate);
		building.setUpdateUser(userName);
		buildingDao.update(building);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void deleteBuilding(Building building) throws Exception {
		buildingDao.delete(building);
	}

	@Transactional(readOnly = true)
	public Floor getFloorById(long id) throws Exception {
		return floorDao.getById(id);
	}

	@Transactional(readOnly = true)
	public List<Floor> getAllFloors() throws Exception {
		return floorDao.findAll();
	}

	public List<Floor> getFloors(String search) throws Exception {
		return getFloors(null, search);
	}

	public List<Floor> getFloors(Building building) throws Exception {
		return getFloors(building, null);
	}

	public List<Floor> getFloors(Building building, String search) throws Exception {
		return getFloors(building, search, Status.ALL);
	}

	@Transactional(readOnly = true)
	public List<Floor> getFloors(Building building, String search, String status) throws Exception {
		return floorDao.findFloors(building, search, status);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void createFloor(Floor floor, String userName) throws Exception {
		Date currentDate = new Date();
		floor.setCreateDate(currentDate);
		floor.setCreateUser(userName);
		floor.setUpdateDate(currentDate);
		floor.setUpdateUser(userName);
		floorDao.create(floor);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void updateFloor(Floor floor, String userName) throws Exception {
		Date currentDate = new Date();
		floor.setUpdateDate(currentDate);
		floor.setUpdateUser(userName);
		floorDao.update(floor);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void deleteFloor(Floor floor) throws Exception {
		floorDao.delete(floor);
	}

	@Transactional(readOnly = true)
	public Room getRoomById(long id) throws Exception {
		return roomDao.getById(id);
	}

	@Transactional(readOnly = true)
	public List<Room> getAllRooms() throws Exception {
		return roomDao.findAll();
	}

	public List<Room> getRooms(Building building) throws Exception {
		return getRooms(building, null, null);
	}

	public List<Room> getRooms(Building building, Floor floor) throws Exception {
		return getRooms(building, floor, null);
	}

	public List<Room> getRooms(Building building, Floor floor, String search) throws Exception {
		return getRooms(building, floor, search, Status.ALL);
	}

	@Transactional(readOnly = true)
	public List<Room> getRooms(Building building, Floor floor, String search, String status) throws Exception {
		return roomDao.findRooms(building, floor, search, status);
	}

	public List<Room> getRooms(Floor floor) throws Exception {
		return getRooms(null, floor, null);
	}

	public List<Room> getRooms(Floor floor, String search) throws Exception {
		return getRooms(null, floor, search);
	}

	public List<Room> getRooms(String search) throws Exception {
		return getRooms(null, null, search);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void createRoom(Room room, String userName) throws Exception {
		Date currentDate = new Date();
		room.setCreateDate(currentDate);
		room.setCreateUser(userName);
		room.setUpdateDate(currentDate);
		room.setUpdateUser(userName);
		roomDao.create(room);

	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void updateRoom(Room room, String userName) throws Exception {
		Date currentDate = new Date();
		room.setUpdateDate(currentDate);
		room.setUpdateUser(userName);
		roomDao.update(room);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void deleteRoom(Room room) throws Exception {
		roomDao.delete(room);
	}

	@Transactional(readOnly = true)
	public Machine getMachineById(long id) throws Exception {
		return machineDao.getById(id);
	}

	@Transactional(readOnly = true)
	public List<Machine> getAllMachines() throws Exception {
		return machineDao.findAll();
	}

	public List<Machine> getMachines(Building building) throws Exception {
		return getMachines(building, null, null, null);
	}

	public List<Machine> getMachines(Building building, Floor floor) throws Exception {
		return getMachines(building, floor, null, null);
	}

	public List<Machine> getMachines(Building building, Floor floor, Room room) throws Exception {
		return getMachines(building, floor, room, null);
	}

	public List<Machine> getMachines(Building building, Floor floor, Room room, String search) throws Exception {
		return getMachines(building, floor, room, search, Status.ALL);
	}

	@Transactional(readOnly = false)
	public List<Machine> getMachines(Building building, Floor floor, Room room, String search, String status) throws Exception {
		return machineDao.findMachines(building, floor, room, search, status);
	}

	public List<Machine> getMachines(Floor floor) throws Exception {
		return getMachines(null, floor, null, null);
	}

	public List<Machine> getMachines(Floor floor, Room room) throws Exception {
		return getMachines(null, floor, room, null);
	}

	public List<Machine> getMachines(Floor floor, Room room, String search) throws Exception {
		return getMachines(null, floor, room, search);
	}

	public List<Machine> getMachines(Room room) throws Exception {
		return getMachines(null, null, room, null);
	}

	public List<Machine> getMachines(Room room, String search) throws Exception {
		return getMachines(null, null, room, search);
	}

	public List<Machine> getMachines(String search) throws Exception {
		return getMachines(null, null, null, search);
	}

	@Transactional(readOnly = false)
	public Machine getMachineByNid(int nid) {
		int gateNo = machineCommandService.getGateNo(nid);
		int deviceNo = machineCommandService.getDeviceNo(nid);
		return machineDao.findMachineByGateAndDeviceNo(gateNo, deviceNo);
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void createMachine(Machine machine, String userName) throws Exception {
		Date currentDate = new Date();
		machine.setCreateDate(currentDate);
		machine.setCreateUser(userName);
		machine.setUpdateDate(currentDate);
		machine.setUpdateUser(userName);
		machineDao.create(machine);
		
		short nid = machineCommandService.getShortNid(machine.getGateNo(), machine.getDeviceNo());
		
		WriteMachineData writeMachineData = writeMachineDataService.select(nid);
		
		if (null == writeMachineData) {	
			writeMachineData = new WriteMachineData();
			writeMachineData.setNid(nid);
			writeMachineData.setCmd("");
			writeMachineDataService.insert(writeMachineData);
		}
		
		ReadMachineData readMachineData = readMachineDataService.selectByNid(nid);
		if(null == readMachineData){
			readMachineData = new ReadMachineData();
			
			int idx = readMachineDataService.getMaxReadMachineDataIdx() + 1;
			readMachineData.setIdx(idx);
			Integer intNid = new Integer(nid);
			readMachineData.setNid(intNid);			
			readMachineData.setLink(0);
			readMachineData.setRcmd("0");
					
			readMachineDataService.insert(readMachineData);
		}

	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void updateMachine(Machine machine, String userName) throws Exception {
		
		//Delete last nid 1st
		long machineId = machine.getMachineId();
		Machine last = machineDao.getById(machineId);
		short lastNid = machineCommandService.getShortNid(last.getGateNo(), last.getDeviceNo());
		
		WriteMachineData writeMachineData = writeMachineDataService.select(lastNid);
		
		if (null != writeMachineData) {			
			writeMachineDataService.delete(writeMachineData);
		}
		
		ReadMachineData readMachineData = readMachineDataService.selectByNid(lastNid);
		if(null != readMachineData){
			readMachineDataService.delete(readMachineData);
		}
		
		Date currentDate = new Date();
		machine.setUpdateDate(currentDate);
		machine.setUpdateUser(userName);
		machineDao.update(machine);
		
		short nid = machineCommandService.getShortNid(machine.getGateNo(), machine.getDeviceNo());
		
		writeMachineData = writeMachineDataService.select(nid);
		
		if (null == writeMachineData) {	
			writeMachineData = new WriteMachineData();
			writeMachineData.setNid(nid);
			writeMachineData.setCmd("");
			writeMachineDataService.insert(writeMachineData);
		}
		
		readMachineData = readMachineDataService.selectByNid(nid);
		if(null == readMachineData){
			readMachineData = new ReadMachineData();
			
			int idx = readMachineDataService.getMaxReadMachineDataIdx() + 1;
			readMachineData.setIdx(idx);
			Integer intNid = new Integer(nid);
			readMachineData.setNid(intNid);			
			readMachineData.setLink(0);
			readMachineData.setRcmd("0");
					
			readMachineDataService.insert(readMachineData);
		}
		
	}

	@Transactional
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	public void deleteMachine(Machine machine) throws Exception {
		machineDao.delete(machine);
		
		short nid = machineCommandService.getShortNid(machine.getGateNo(), machine.getDeviceNo());
		
		
		WriteMachineData writeMachineData = writeMachineDataService.select(nid);
		
		if (null != writeMachineData) {			
			writeMachineDataService.delete(writeMachineData);
		}
		
		ReadMachineData readMachineData = readMachineDataService.selectByNid(nid);
		if(null != readMachineData){

			readMachineDataService.delete(readMachineData);
		}
		
		
	}

	@Transactional
	public Floor getFloorDetail(long id) throws Exception {
		Floor floor = floorDao.getById(id);
		floor.getFloorPlan();
		return floor;
	}
		

}
